昨天討論了在 Python 中的三種浮點數簡化:truncate, flooring, ceiling。今天我們來學習最後一種有趣的簡化方法:round
help(round)
Help on built-in function round in module builtins:
round(number, ndigits=None)
Round a number to a given precision in decimal digits.
The return value is an integer if ndigits is omitted or None. Otherwise
the return value has the same type as the number. ndigits may be negative.
看上述說明可以得知,round
會把數值簡化到小數點後 ndigits 位,預設是第0位,也就是回傳一個整數:
round(1.234)
1
你也可以指定 round
到小數點後幾位數:
round(1.234, 2)
1.23
小數點後幾位數可以是“負“的,代表 round
到小數點前幾位數:
round(123.45, -1)
120.0
round
的意思是根據你指定要簡化到的位數,回傳最靠近的數字:
round(100.1), round(100.7)
(100, 101)
不過,如果數字剛好在中間怎麼辦呢?我們從小學到的規則就叫:四捨五入。
Python應該也是如此,對吧?
round(1.35, 1)
1.4
看起來是四捨五入,為了保險我們再測試一個數字好了:
round(1.25, 1)
1.2
怪事發生了!round(1.25, 1)
答案竟然是 1.2 ?
為什麼?
其實 Python 使用的並非四捨五入,而是一種叫做 banker rounding 的簡化規則,什麼是 banker rounding?
根據 IEEE standard 的解釋:
Rounds to the nearest value, with ties rounded to the nearest value with an
even least significant digit.
意思是,若數值在中間,簡化到最小有效位數的偶數。
這是什麼意思?檢查下面的範例:
round(1.35, 1), round(1.25, 1)
(1.4, 1.2)
第一個數字 1.35
在 1.3 和 1.4 的正中間,round 到小數點後第一位,選擇偶數的 1.4。
第一個數字 1.25
在 1.2 和 1.3 的正中間,round 到小數點後第一位,選擇偶數的 1.2。
為什麼要用這種 banker rounding 演算法?
顧名思義,這是銀行行員會想用的算法,為什麼呢?因為單純的四捨五入,可能會讓銀行損失慘重。
假設有一個人存了四筆錢進銀行:1.5元, 2.5元, 3.5元, 4.5元,四筆錢四捨五入後加起來平均:
(2 + 3 + 4 + 5) / 4 = 14 / 4 = 3.5
跟真正的值 (1.5 + 2.5 + 3.5 + 4.5) / 4 = 12 / 4 = 3 比起來多了 0.5 元。
我們可以發現四捨五入是一種不斷遠離零的近似方式。
那 banker rounding 呢?我們用上面存錢的例子測試:
saved = round(1.5) + round(2.5) + round(3.5) + round(4.5)
print(saved, saved / 4)
12 3.0
這才接近真正存入的錢!banker rounding 解決了普通四捨五入讓數字不斷膨脹的問題。
好了,我們明天見!
參考:Python 3: Deep Dive (Part 1 - Functional)
是bankers' rounding
, banker's rounding
, 或bankers rounding
,不是banker rounding
。